package com.example.springbootdemo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springbootdemo.dao.pdfFillMapper;
import com.example.springbootdemo.pojo.pdfFill;
import com.example.springbootdemo.service.pdfFillService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDPushButton;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

/**
 * pdfFillImpl
 * 说明：因为图片的处理，不是用OSS服务器线上存储，而是本地数据存储，所以需要字节数组处理图片
 * TODO 1、OSS线上存储，客户端直传
 * @date: 2025/7/22 18:30
 * @version: 1.0
 */
@Service
@Slf4j
public class pdfFillImpl extends ServiceImpl<pdfFillMapper, pdfFill> implements pdfFillService {
    @Override
    public void fillPdf(Map<String,String> formData,  Map<String, byte[]> imageData, HttpServletResponse response) throws IOException {
        try {
            // 使用 ByteArrayOutputStream 替代文件输出流
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            // 加载模板并填充数据（原有逻辑保持不变）
            ClassPathResource resource = new ClassPathResource("模板.pdf");
            InputStream inputStream = resource.getInputStream();
            PDDocument pdfDocument = PDDocument.load(inputStream);

            PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();

            if (acroForm != null) {

                // 加载并嵌入支持中文的字体
                InputStream fontStream = new ClassPathResource("simhei.ttf").getInputStream();// 加载字体
                PDType0Font chineseFont = PDType0Font.load(pdfDocument, fontStream, false);

                // 获取或创建AcroForm的默认资源
                PDResources defaultResources = acroForm.getDefaultResources();
                if (defaultResources == null) {
                    defaultResources = new PDResources();
                }
                // 将字体添加到AcroForm的默认资源中
                defaultResources.put(org.apache.pdfbox.cos.COSName.getPDFName("F0"), chineseFont);
                acroForm.setDefaultResources(defaultResources); // 确保AcroForm更新其资源字典

                for (Map.Entry<String, String> entry : formData.entrySet()) {
                    // 确保字段是文本字段    处理文本域
                    PDField field = acroForm.getField(entry.getKey());  // 为特定的字段设置中文内容
                    if (field != null && field instanceof PDTextField) { // 确保字段是文本字段
                        PDTextField textField = (PDTextField) field;

                        String fieldName = field.getPartialName();

                        String textToFill = entry.getValue();
                        float fontSize = 12; // Default size

                        textField.setValue(textToFill); // 确保字段的内部值也被设置，放在部件处理之前

                        // 遍历所有部件并为其手动创建外观流
                        for (PDAnnotationWidget widget : textField.getWidgets()) {
                            // 手动为文本字段创建外观流
                            PDAppearanceStream textAppearanceStream = new PDAppearanceStream(pdfDocument);
                            PDRectangle fieldRect = widget.getRectangle(); // 获取部件的矩形
                            textAppearanceStream.setBBox(fieldRect);
                            PDResources textResources = new PDResources();
                            // 将字体添加到这个特定的外观流的资源中，使用F0作为别名
                            textResources.put(org.apache.pdfbox.cos.COSName.getPDFName("F0"), chineseFont);
                            textAppearanceStream.setResources(textResources);

                            PDPageContentStream textContentStream = new PDPageContentStream(pdfDocument, textAppearanceStream);
                            textContentStream.beginText();
                            textContentStream.setFont(chineseFont, fontSize);
                            textContentStream.setNonStrokingColor(0, 0, 0); // 黑色
                            // 根据字段矩形定位文本，这里需要根据实际需求调整X和Y的偏移量
                            // 简单示例：从左下角开始绘制，实际应用可能需要计算居中或特定对齐
                            textContentStream.newLineAtOffset(fieldRect.getLowerLeftX(), fieldRect.getLowerLeftY() + (fieldRect.getHeight() - fontSize) / 2);
                            textContentStream.showText(textToFill);
                            textContentStream.endText();
                            textContentStream.close();

                            PDAppearanceDictionary textAppearanceDictionary = new PDAppearanceDictionary();
                            textAppearanceDictionary.setNormalAppearance(textAppearanceStream);
                            widget.setAppearance(textAppearanceDictionary); // 设置部件的外观
                        }

                    }

                }

                for (Map.Entry<String, byte[]> imageEntry : imageData.entrySet()) {
                    // 确保字段是图片字段    处理图片域
                    PDField imageField = acroForm.getField(imageEntry.getKey());

                    if (imageField != null && imageField instanceof PDPushButton) {
                        PDPushButton button = (PDPushButton) imageField;

                        // 如果 imageEntry.getValue() 是file，createFromFile 加载图片；imageEntry.getValue() = 本地图片路径
                        // PDImageXObject image = PDImageXObject.createFromFile(imageEntry.getValue(), pdfDocument);
                        // 如果 imageEntry.getValue() 是字节流（二进制数据），createFromByteArray 加载图片
                        byte[] fileBytes = imageEntry.getValue();
                        PDImageXObject image = PDImageXObject.createFromByteArray(pdfDocument, fileBytes, "image");

                        // 创建一个表单XObject来包含图片
                        PDRectangle buttonRect = button.getWidgets().get(0).getRectangle(); // 获取按钮的矩形区域
                        PDFormXObject formXObject = new PDFormXObject(pdfDocument);
                        formXObject.setBBox(buttonRect); // 设置XObject的边界框为按钮的矩形
                        formXObject.setResources(new PDResources()); // 添加资源字典

                        // 创建内容流并将图片绘制到XObject中
                        PDAppearanceStream appearanceStream = new PDAppearanceStream(pdfDocument);
                        appearanceStream.setBBox(buttonRect); // 设置XObject的边界框为按钮的矩形
                        appearanceStream.setResources(new PDResources()); // 添加资源字典

                        PDPageContentStream contentStream = new PDPageContentStream(pdfDocument, appearanceStream);
                        // 计算图片在新区域内的缩放和位置
                        float imageWidth = image.getWidth();
                        float imageHeight = image.getHeight();
                        float buttonWidth = buttonRect.getWidth();
                        float buttonHeight = buttonRect.getHeight();

                        float scale = Math.min(buttonWidth / imageWidth, buttonHeight / imageHeight);
                        float scaledWidth = imageWidth * scale;
                        float scaledHeight = imageHeight * scale;

                        float x = buttonRect.getLowerLeftX() + (buttonWidth - scaledWidth) / 2;
                        float y = buttonRect.getLowerLeftY() + (buttonHeight - scaledHeight) / 2;

                        contentStream.drawImage(image, x, y, scaledWidth, scaledHeight);
                        contentStream.close();

                        // 创建PDAppearanceDictionary并设置其内容流
                        PDAppearanceDictionary appearanceDictionary = new PDAppearanceDictionary();
                        appearanceDictionary.setNormalAppearance(appearanceStream);

                        // 设置按钮的正常外观
                        button.getWidgets().get(0).setAppearance(appearanceDictionary);
                    } else if (imageField != null) {
                        throw new RuntimeException("Image field " + imageEntry.getKey() + " cannot be used for image insertion in this manner (expected PDPushButton).");
                    } else {
                        throw new RuntimeException("Image field " + imageEntry.getKey() + " not found in the PDF template.");
                    }

                }

            } else {
                throw new RuntimeException("PDF文档不包含AcroForm表单。");
            }

            // 1. 将PDF内容写入字节数组
            pdfDocument.save(outputStream);
            //  pdfDocument.save("C:/Users/xxxx/Downloads/test.pdf");   // 本地测试是否生成pdf成功
            pdfDocument.close();

            // 2. 设置响应头     response.setContentType("application/pdf");
            response.setContentType(String.valueOf(MediaType.APPLICATION_PDF));
            // 设置文件名和下载属性（建议动态生成文件名
            String fileName = "test" + ".pdf";
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            response.setContentLength(outputStream.toByteArray().length);

            // 3. 将字节数组写入响应输出流
            try (OutputStream out = response.getOutputStream()) {
                out.write(outputStream.toByteArray());
                out.flush();
            }
            response.flushBuffer();

        } catch (Exception e) {
            // 4. 异常处理（可根据需要自定义错误响应）
//             throw new RuntimeException("PDF生成失败: " + e.getMessage(), e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "PDF生成失败: " + e.getMessage());
        }
    }

}
